package com.cloudptt.api.pjsua2;

import android.content.Context;
import android.content.Intent;

import com.cloudptt.api.comm.CauseCont;
import com.cloudptt.api.models.SipMsgParser;
import com.cloudptt.api.models.call.CallExtStrInfo;
import com.cloudptt.api.models.msg.MsgExtStrInfo;
import com.cloudptt.api.pjsip.api.SipCallSession;
import com.cloudptt.api.pjsip.api.SipManager;
import com.cloudptt.api.product.func.call.CallAttr;
import com.cloudptt.api.product.log.Log;
import com.mcptt.db.model.AddrInfo;

import org.pjsip.pjsua2.Account;
import org.pjsip.pjsua2.AccountConfig;
import org.pjsip.pjsua2.AuthCredInfo;
import org.pjsip.pjsua2.AuthCredInfoVector;
import org.pjsip.pjsua2.BuddyConfig;
import org.pjsip.pjsua2.CallInfo;
import org.pjsip.pjsua2.OnIncomingCallParam;
import org.pjsip.pjsua2.OnInstantMessageParam;
import org.pjsip.pjsua2.OnRegStateParam;
import org.pjsip.pjsua2.SendInstantMessageParam;
import org.pjsip.pjsua2.SendTypingIndicationParam;
import org.pjsip.pjsua2.SipHeader;
import org.pjsip.pjsua2.SipHeaderVector;
import org.pjsip.pjsua2.StringVector;
import org.pjsip.pjsua2.TransportConfig;

import java.util.HashMap;
import java.util.Iterator;

public class MyAccount extends Account
{
    public static String TAG = "MyAccount";

    private Context ctx = null;
    private String num = null;
    public AccountConfig accCfg;
//    public MyCall call = null;
    private AuthCredInfoVector creds = null;
    private StringVector proxies = null;
    private TransportConfig config = null;

    private SipHeaderVector vec = null;
    private SipHeader header = null;
    private MyBuddy bud = null;
    private SendTypingIndicationParam param = null;

    private HashMap<String,MyCall> callMap = new HashMap<String,MyCall>();
    private String allGroupNum = "";
    private String curCallGNum = "";
    private float txLevel = 0;
    private float rxLevel = 0;

    MyAccount(Context ctx,String domain,String idUrl,String pwd, String regJson,float txLevel,float rxLevel)
    {
        super();
        this.ctx = ctx;
        this.num = idUrl;
        this.txLevel = txLevel;
        this.rxLevel = rxLevel;

        accCfg = new AccountConfig();
        accCfg.setIdUri(idUrl);
        accCfg.getNatConfig().setIceEnabled(false);
        accCfg.getNatConfig().setContactRewriteUse(1);
        accCfg.getNatConfig().setUdpKaIntervalSec(0);
        accCfg.getVideoConfig().setAutoTransmitOutgoing(true);
        accCfg.getVideoConfig().setAutoShowIncoming(true);
        //accCfg.getVideoConfig().setDefaultCaptureDevice(PJMEDIA_VID_DEFAULT_CAPTURE_DEV);

        String regUri = "sip:" + domain;
        Log.d(TAG, "addAccount regUri = " + regUri);
        accCfg.getRegConfig().setRegistrarUri(regUri);
        accCfg.getRegConfig().setTimeoutSec(65535);
        accCfg.getSipConfig().setRegJson(regJson);
        creds = accCfg.getSipConfig().
                getAuthCreds();
        creds.clear();
        if (num.length() != 0) {
            creds.add(new AuthCredInfo("Digest", "*", num, 0,
                    pwd));
        }
        proxies = accCfg.getSipConfig().getProxies();
        proxies.clear();
        String proxy = "";
        if (proxy.length() != 0) {
            proxies.add(proxy);
        }
//        this.num = num;


        Log.d(TAG, "MyAccount accCfg = " + accCfg);
    }

    public void create() throws Exception
    {
        this.create(accCfg);
    }
    public int setCallGNum(String allGroupNum,String curGroupNum,String sosGroupNum,String selfNum) {
        this.allGroupNum = allGroupNum;
        if(callMap != null
                && callMap.size() > 0)
        {
            for (Iterator<String> itor = callMap.keySet().iterator(); itor.hasNext(); ) {
                String key = itor.next();
                if(callMap.get(key) != null)
                {
                    MyCall call = callMap.get(key);
                    if(call != null) {
                    call.setCallGNum(this.allGroupNum,curGroupNum,sosGroupNum,selfNum);
                    }
                }
            }
        }
        return 0;
    }


    public int sendMessage(final int sessionType,final int msgType,final long len,final String message, final String recver)
    {
        Log.d(TAG, "addBuddy recver = " + recver);
        /* Create Buddy */
        BuddyConfig cfg = new BuddyConfig();
        String sipUrl = AddrInfo.toSipUrlFromNum(recver);
        Log.d(TAG, "addBuddy sipUrl = " + sipUrl);
        cfg.setUri(sipUrl);
        cfg.setSubscribe(false);
        MyBuddy bud = new MyBuddy(cfg);
        try {
            bud.create(this, cfg);
        } catch (Exception e) {
            bud.delete();
            bud = null;
        }
        SendInstantMessageParam prm = new SendInstantMessageParam();
        try {
            MsgExtStrInfo info = new MsgExtStrInfo(sessionType,msgType,recver);
            if(info != null)
            {
                SipHeaderVector vec = new SipHeaderVector();
                SipHeader header = new SipHeader();
                header.setHName("CallInfo");
                header.setHValue(info.toString());
                vec.add(header);
                prm.getTxOption().setHeaders(vec);
                prm.setContentType("application/json;charset=UTF-8");
                prm.setContent(message);
            }
            bud.sendInstantMessage(prm);
            bud.delete();
            bud = null;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return CauseCont.OperateErr_Exception;
        }
        return CauseCont.OperateCheck_Suc;
    }

    public int sendSosMessage()
    {
        Log.d(TAG, "sendSosMessage");
        /* Create Buddy */
        BuddyConfig cfg = new BuddyConfig();
        String sipUrl = AddrInfo.toSipUrlFromNum("88888888");
        Log.d(TAG, "addBuddy sipUrl = " + sipUrl);
        cfg.setUri(sipUrl);
        cfg.setSubscribe(false);
        MyBuddy bud = new MyBuddy(cfg);
        try {
            bud.create(this, cfg);
        } catch (Exception e) {
            bud.delete();
            bud = null;
        }
        SendInstantMessageParam prm = new SendInstantMessageParam();
        try {
            SipHeaderVector vec = new SipHeaderVector();
            SipHeader header = new SipHeader();
            header.setHName("CallInfo");
            String val = AddrInfo.toNumFromSipUrl(num);
            header.setHValue("Alarm;Ctype=orig;AlarmNum=" + val);
            vec.add(header);
            prm.getTxOption().setHeaders(vec);

            bud.sendInstantMessage(prm);
            bud.delete();
            bud = null;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return CauseCont.OperateErr_Exception;
        }
        return CauseCont.OperateCheck_Suc;
    }
	
    @Override
    public void onRegState(OnRegStateParam prm)
    {
        long accId = this.getId();
        Log.d(TAG, "onRegState prm : accId = " + accId + " code = " + prm.getCode() + "; exp = " + prm.getExpiration());

        long expiration = prm.getExpiration();

        int code = prm.getCode();
		if (code == 200 && expiration == 0) {//??????
            return;
        }
        if (code == 503) {//status=503 (Transport not available for use (PJSIP_ETPNOTAVAIL))
            return;
        }

        Log.d(TAG, "onRegState code = " + code);
        Intent intent = new Intent(SipManager.ACTION_SIP_REG);
        //intent.addFlags( code);
        intent.putExtra(SipManager.RESULT_CODE,code);
        String str = AddrInfo.toNumFromSipUrl(num);
        intent.putExtra(SipManager.RESULT_NUM, str);

        if (code/100 == 2)
            intent.putExtra(SipManager.RESULT_NAME, AddrInfo.getDefaultName(str));
        else
            intent.putExtra(SipManager.RESULT_NAME, "");

        ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
//        MyApp.observer.notifyRegState(prm.getCode(), prm.getReason(),
//                prm.getExpiration());
    }

    @Override
    public void onIncomingCall(OnIncomingCallParam prm)
    {
        Log.d(TAG, "onIncomingCall prm = " + prm);
        MyCall call = new MyCall(ctx,this, prm.getCallId(), allGroupNum,curCallGNum,txLevel,rxLevel);

        CallInfo info = null;
        String callExStr = "";
        String fromStr = "";
        int callType = CallAttr.CallType_Single;
        CallExtStrInfo extStrInfo = null;
        try {
            info = call.getInfo();
            String allMsgStr = prm.getRdata().getWholeMsg();
            SipMsgParser parser = new SipMsgParser(allMsgStr);
            callExStr = parser.getExStr();
            Log.d(TAG, "onIncomingCall callExStr = " + callExStr);
            fromStr = parser.getFromStr();
            Log.d(TAG, "onIncomingCall fromStr = " + fromStr);

            extStrInfo = new CallExtStrInfo(callExStr);
			boolean hasVideo = extStrInfo.hasVideo();
            Log.d(TAG, "onIncomingCall info.getRemVideoCount() = " + info.getRemVideoCount());
            if(info.getRemVideoCount() > 0)
            {
                hasVideo = true;
            }

            Log.d(TAG, "onIncomingCall fromStr = " + fromStr + "\n extStrInfo = " + extStrInfo);
            if(extStrInfo != null)
            {
                callType = extStrInfo.getCallType();
                Log.d(TAG, "onIncomingCall callType = " + callType);
                if(callType == CallAttr.CallType_Single)
                {
                     call.answer(180,hasVideo);
                }
            }
            String callKey = info.getCallIdString();
            call.updateCallInfo(callKey,callType,CallAttr.CallDir_MT);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return;
        }


        if(info != null)
        {
            try {
                SipCallSession session = SipCallSession.toSipCallSession(info,extStrInfo,fromStr);
                session.setIncoming(true);
                Log.d(TAG, "onIncomingCall 2 info.getRemVideoCount() = " + info.getRemVideoCount());
                if(info.getRemVideoCount() > 0)
                {
                    session.setUseVideo(true);
                }
                call.setSession(session);
                this.addMyCall(info.getCallIdString(),call);
                Log.d(TAG, "onIncomingCall 2 callType = " + callType);
                if(callType == CallAttr.CallType_Group
                        || callType == CallAttr.CallType_Single_half)
                {
                    Intent intent = new Intent(SipManager.ACTION_SIP_CALL_INCOMING);
                    intent.putExtra(SipManager.EXTRA_CALL_INFO, session);
                    ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                }
                else if(callType == CallAttr.CallType_Single
                        || callType == CallAttr.CallType_Video_Push
                        || callType == CallAttr.CallType_Video_Pull
                        || callType == CallAttr.CallType_Video_Trans
                        || callType == CallAttr.CallType_Video_TransGrp
                        || callType == CallAttr.CallType_Video_PushGrp)
                {
                    Intent intent = new Intent(SipManager.ACTION_SINGLE_CALL_INCOMING);
                    intent.putExtra(SipManager.EXTRA_CALL_INFO, session);
                    ctx.sendBroadcast(intent, SipManager.PERMISSION_USE_SIP);
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public void clean()
    {
        if(callMap != null
            && callMap.size() > 0)
        {
            for (Iterator<String> itor = callMap.keySet().iterator(); itor.hasNext(); ) {
                String key = itor.next();
                if(callMap.get(key) != null)
                {
                    MyCall call = callMap.get(key);
                    if(call != null)
                    {
                        call.delete();
                        call = null;
                    }
                    itor.remove();
                }
            }
        }
        this.delete();
    }

    @Override
    public void onInstantMessage(OnInstantMessageParam prm)
    {
        Log.d(TAG, "onInstantMessage prm = " + prm);
        System.out.println("======== Incoming pager ======== ");
        System.out.println("From     : " + prm.getFromUri());
        System.out.println("To       : " + prm.getToUri());
        System.out.println("Contact  : " + prm.getContactUri());
        System.out.println("Mimetype : " + prm.getContentType());
        System.out.println("Body     : " + prm.getMsgBody());

//        String msgType = prm.getContentType();
        String bodyStr = prm.getMsgBody();
        Log.d(TAG, "onInstantMessage bodyStr = " + bodyStr);

        String allMsgStr = prm.getRdata().getWholeMsg();
        SipMsgParser parser = new SipMsgParser(allMsgStr);
        String exStr = parser.getExStr();
        Log.d(TAG, "onInstantMessage exStr = " + exStr);

        if(bodyStr.contains("GrpProfileChange"))
        {
            Intent intent = new Intent(SipManager.ACTION_SIP_ADDR_UPT);
//            intent.putExtra(SipManager.Body_Str, bodyStr);
            ctx.sendBroadcast(intent,
                    SipManager.PERMISSION_USE_SIP);
        }

        if(exStr.contains("onlinestatus"))
        {
            Intent intent = new Intent(SipManager.ACTION_SIP_ONLINE);
            intent.putExtra(SipManager.Body_Str, bodyStr);
            ctx.sendBroadcast(intent,
                    SipManager.PERMISSION_USE_SIP);
        }
        else if(exStr.contains("applog;attr1"))
        {
            Intent intent = new Intent(SipManager.ACTION_SIP_APPLOG);
            ctx.sendBroadcast(intent,
                    SipManager.PERMISSION_USE_SIP);
        }
        else if(exStr.toLowerCase().contains("alarm;alarmnum"))
        {
            Log.d(TAG, "onInstantMessage sos");
            Intent intent = new Intent(SipManager.ACTION_SIP_SOS);
            intent.putExtra(SipManager.Info_Str, exStr);
            ctx.sendBroadcast(intent,
                    SipManager.PERMISSION_USE_SIP);
        }
        else {
            Intent intent = new Intent(SipManager.ACTION_SIP_MESSAGE);
            intent.putExtra(SipManager.Body_Str, bodyStr);
            String num = AddrInfo.toNumFromSipUrl(prm.getFromUri());
            intent.putExtra(SipManager.FROML_STR, num);
            intent.putExtra(SipManager.Info_Str, exStr);
            ctx.sendBroadcast(intent,
                    SipManager.PERMISSION_USE_SIP);
        }

    }
    public String toString()
    {
        StringBuffer strBuf = new StringBuffer();
        strBuf.append("MyAccount").append(";");
        strBuf.append("accCfg").append("=").append(accCfg).append(";");
        strBuf.append("Id").append("=").append(this.getId()).append(";");
        strBuf.append("num").append("=").append(num).append(";");
        try {
            strBuf.append("Info").append("=").append(this.getInfo()).append(";");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return strBuf.toString();
    }
    public String getNum() {
        return num;
    }


    public String getNewCallIdStr(int callType,int callDir)
    {
        Log.d(TAG, "addMyCall callMap = " + callMap);
        MyCall call = new MyCall(ctx,this, -1, allGroupNum,curCallGNum,txLevel,rxLevel);
        call.updateCallInfo(MyCall.DEF_CALL_ID_STR,callType,callDir);
        callMap.put(MyCall.DEF_CALL_ID_STR,call);
        return MyCall.DEF_CALL_ID_STR;
    }
    public void addMyCall(String callIdStr,MyCall call) {
//        this.call = call;
        Log.d(TAG, "addMyCall callIdStr = " + callIdStr);
        Log.d(TAG, "addMyCall callMap = " + callMap);
        if(callMap != null
            && callMap.get(callIdStr) != null)
        {
            callMap.remove(callIdStr);
        }
        if(callMap != null
                && callIdStr != null)
        {
            callMap.put(callIdStr,call);
        }
    }
    public void delMyCall(String callIdStr) {
        Log.d(TAG, "delMyCall callIdStr = " + callIdStr);
        Log.d(TAG, "delMyCall callMap = " + callMap);
        if(callMap != null
                && callIdStr != null)
        {
            callMap.remove(callIdStr);
        }
    }
    public MyCall getMyCall(String callIdStr) {
        Log.d(TAG, "getMyCall callIdStr = " + callIdStr);
        Log.d(TAG, "getMyCall callMap = " + callMap);
        if(callMap != null)
        {
            return callMap.get(callIdStr);
        }
        return null;
    }

    public int checkSystemErr()
    {
        Log.e(TAG, "checkSystemErr num is " + num);
        if(num == null
                || num.equals(""))
        {
            return CauseCont.OperateCheck_Sys_AccountNumNull;
        }

        return CauseCont.OperateCheck_Suc;
    }
//    private int checkCall()
//    {
//        Log.e(TAG, "checkIsMySelf num is " + num);
////        if(num == null
////                || num.equals(""))
////        {
////            return CauseCont.OperateCheck_Call_NumNull;
////        }
//
//        Log.e(TAG, "checkIsMySelf myNum is " + myNum + " num is " + num);
//        if(num == null
//                || num.equals(""))
//        {
//            return CauseCont.OperateCheck_Call_NumNull;
//        }
//        return CauseCont.OperateCheck_Suc;
//    }
}
